﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ARNative;
using System.Web.Mvc;

namespace NRemedy.MVC.UI
{
    public class TreeController : SessionController
    {
        [JsonExceptionHandler]
        public virtual ActionResult Query(string form, FormCollection TIdCollection, string qu, string Top)
        {
            TreeRequest request = Parse(form, TIdCollection, qu, Top);
            return QueryInternal(ARUserSession.ARContext, request);
        }

        [NonAction]
        public virtual ActionResult QueryInternal(ARLoginContext context, TreeRequest request)
        {
            try
            {
                int totalMatch = -1;
                var entries = context.ServerInstance.GetEntryList(request.FormName,
                    request.Qualification, request.Merge(),
                    0, null, ref totalMatch, request.Sorts);
                return JsonToTreeFromEntries(entries, request, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        [NonAction]
        public virtual TreeRequest Parse(string form, FormCollection TIdCollection, string qu, string Top)
        {
            List<uint> fieldIds = new List<uint>();
            string sort = null;
            string order = null;
            string fieldsStr = null;
            Dictionary<string, uint> selected = new Dictionary<string, uint>();

            foreach (var key in TIdCollection.AllKeys)
            {
                if (key == "sort")
                    sort = TIdCollection[key];
                else if (key == "order")
                    order = TIdCollection[key];
                else if (key == "fields")
                    fieldsStr = TIdCollection[key];
                else if (key == "qu")
                    continue;
                else
                    selected.Add(key, Convert.ToUInt32(TIdCollection[key]));
            }

            //prepare fieldId list
            foreach (var id in fieldsStr.Split('|'))
            {
                if (string.IsNullOrEmpty(id)) continue;
                fieldIds.Add(Convert.ToUInt32(id));
            }


            //prepare sortorder
            List<ARSortInfo> arsi = null;
            if (sort != null && order != null)
            {
                ARSortInfo si = new ARSortInfo();
                if (order == "desc")
                    si.Order = SortOrder.SORT_DESCENDING;
                else
                    si.Order = SortOrder.SORT_ASCENDING;
                si.FieldId = Convert.ToUInt32(sort.Substring(1));
                arsi = new List<ARSortInfo>();
                arsi.Add(si);

            }
            TreeRequest request = new TreeRequest();
            request.FieldIds = fieldIds;
            request.FormName = form;
            request.Qualification = qu;
            request.Top = Top;
            request.Sorts = arsi;
            request.SelectedFieldIds = selected;

            return request;
        }

        [NonAction]
        public virtual JsonResult JsonToTreeFromEntries(IEnumerable<AREntry> entries, TreeRequest request, JsonRequestBehavior behavior)
        {
            //{"text":"xxx","children":[{"text":"xxx","children":[{text:xxx,desc:xxx},{text:xxx,desc:xxx},{text:xxx,desc:xxx}]}]}
            if (entries == null)
                return null;
            var deep = request.FieldIds.GetEnumerator();
            deep.MoveNext();
            uint current = deep.Current;
            bool isLeaf = !deep.MoveNext();
            TreeNode tree = new TreeNode { Text = request.Top };
            BuildTree(null, tree, current, entries, deep, isLeaf);
            JsonBuilder jb = EnumerateTree(tree, request.SelectedFieldIds);

            return new RawJsonResult() { JsonRequestBehavior = behavior, Data = "[" + jb.ToString() + "]" };
        }

        public void BuildTree(uint? parentId, TreeNode parentNode, uint CurrentFieldId,
            IEnumerable<AREntry> entries,
            IEnumerator<uint> deep,
            bool isLeaf
            )
        {
            if (!isLeaf)//not leaf
            {
                IEnumerable<ARFieldValue> k;
                if (parentId != null)
                {
                    k = entries
                        //filter entry where has parentId and parentValue
                    .Where(f => f.FieldValues.FirstOrDefault(z => z.FieldId == parentId && z.Value.ToString() == parentNode.Text) != null)
                    .Select(entry => entry.FieldValues).Select(fvs => fvs.First(arfv => arfv.FieldId == CurrentFieldId));
                }
                else
                {
                    k = entries
                        .Select(entry => entry.FieldValues).Select(fvs => fvs.First(arfv => arfv.FieldId == CurrentFieldId));
                }
                var j = k.Distinct(Equality<ARFieldValue>.CreateComparer(a => a.Value));//.Select(b => b.Value);

                uint next = deep.Current;
                bool leafflag = !deep.MoveNext();

                foreach (var i in j)
                {
                    TreeNode node = new TreeNode();
                    node.Text = i.Value.ToString();
                    BuildTree(CurrentFieldId, node, next, entries, deep, leafflag);
                    parentNode.Next.Add(node);
                }
            }
            else
            {
                Dictionary<object, AREntry> k2 = new Dictionary<object, AREntry>();
                if (parentId != null)
                {
                    foreach (var entry in entries)
                    {
                        if (entry.FieldValues.FirstOrDefault(p => p.FieldId == parentId && p.Value.ToString() == parentNode.Text) != null)
                        {
                            var key = entry.FieldValues.First(f => f.FieldId == CurrentFieldId).Value;
                            k2[key] = entry;
                        }
                    }
                }
                else
                {
                    foreach (var entry in entries)
                    {
                        var key = entry.FieldValues.First(f => f.FieldId == CurrentFieldId).Value;
                        k2[key] = entry;
                    }
                }

                foreach (var each_entry in k2.Values)
                {
                    TreeNode node = new TreeNode();
                    node.Row = each_entry.FieldValues;
                    parentNode.Next.Add(node);
                }
            }
        }

        public JsonBuilder EnumerateTree(TreeNode node, Dictionary<string, uint> leafFields)
        {
            JsonBuilder builder = new JsonBuilder();
            //leaf
            if (node.Next == null || node.Next.Count == 0)
            {
                if (node.Row != null)
                {
                    foreach (var key in leafFields.Keys)
                    {
                        builder.MergeProperty(key, node.Row.First(a => a.FieldId == leafFields[key]).Value);
                    }
                }
            }
            else //not leaf
            {
                builder.MergeProperty("text", node.Text);
                //builder.MergeProperty("id", node.Text);
                foreach (var next in node.Next)
                {
                    JsonBuilder child = EnumerateTree(next, leafFields);
                    builder.MergeChildObject("children", child);
                }

            }

            return builder;

        }
    }
}

